import os
import time
import json
import logging
from flask import request, jsonify
from config import UPLOAD_FOLDER, PROCESSED_FOLDER, SPEECHEMO_FOLDER, EXTERNAL_UPLOAD_URL
import requests
from database import save_to_database, save_session_to_database, update_conversation_text_by_session_no
from audio_processor import process_audio
from minio_manager import minio_manager
from asr_manager import process_audio_speech_emotion
from async_processor import enqueue_job, start_worker

logger = logging.getLogger('flask.app')

def register_routes(app):
    """注册所有路由"""
    # 启动异步工作线程
    try:
        start_worker()
    except Exception:
        logger.warning("异步工作线程启动失败，将继续同步执行")
    
    @app.route('/seat/upload', methods=['POST'])
    def upload_file():
        """处理文件上传请求"""
        try:
            # 记录请求基本信息
            logger.info(f"收到文件上传请求: {request.method} {request.url}")
            
            # 获取请求头中的文件名
            header_file_name = request.headers.get('File-Name', '')
            # 从文件名中提取基础名称（去掉路径部分）
            if header_file_name:
                base_file_name = os.path.basename(header_file_name)
                logger.debug(f"从请求头获取文件名: {base_file_name}")
            else:
                # 如果请求头中没有文件名，生成一个默认文件名
                base_file_name = f"unknown_file_{int(time.time())}.aac"
                logger.warning(f"请求头中未找到File-Name，使用默认文件名: {base_file_name}")
            
            # 尝试获取上传的文件
            sound_recording = None
            if 'soundRecording' in request.files:
                sound_recording = request.files['soundRecording']
                logger.debug("找到soundRecording文件字段")
            
           
            # 获取其他表单字段
            device_no = request.form.get('deviceNo', '')
            chunk_index = request.form.get('chunkIndex', '0')
            start_time = request.form.get('startTime')
            end_time = request.form.get('endTime', '')
            usr_no = request.form.get('usrNo', '')
            has_body = request.form.get('hasBody', 'false').lower() == 'true'
            extended = request.form.get('extended', '')
            logger.error(device_no)
            # 解析extended参数，提取时间对
            extended_data = []
            time_pairs = []  # 存储(inTime, outTime)元组的列表
            
            if extended:
                try:
                    extended_data = json.loads(extended)
                    logger.debug(f"解析extended数据成功: {extended_data}")
                    
                    # 处理交替出现的inTime和outTime
                    current_in_time = None
                    
                    for item in extended_data:
                        if isinstance(item, dict):
                            if 'inTime' in item:
                                # 如果已有未配对的inTime，先保存为(prev_in, None)
                                if current_in_time:
                                    time_pairs.append((current_in_time, None))
                                
                                current_in_time = item['inTime']
                                
                            if 'outTime' in item:
                                # 配对当前inTime和outTime
                                time_pairs.append((current_in_time, item['outTime']))
                                current_in_time = None  # 已配对，重置
                    
                    # 处理最后可能剩下的inTime
                    if current_in_time:
                        time_pairs.append((current_in_time, None))
                        
                    logger.debug(f"提取到时间对: {time_pairs}")
                    
                except json.JSONDecodeError as e:
                    logger.warning(f"解析extended JSON失败: {str(e)}, 原始数据: {extended}")
            
            # 保存文件到MinIO
            minio_url = None
            file_size = 0
            
            local_audio_path = None
            try:
                if sound_recording and sound_recording.filename != '':
                    # 如果有有效的文件，先保存到临时位置
                    temp_file_path = os.path.join(UPLOAD_FOLDER, base_file_name)
                    sound_recording.save(temp_file_path)
                    file_size = os.path.getsize(temp_file_path)
                    logger.info(f"文件保存到临时位置: {temp_file_path}, 大小: {file_size} 字节")
                    local_audio_path = temp_file_path
                    
                    # 上传到MinIO
                    minio_url = minio_manager.upload_file(temp_file_path, base_file_name)
                    if minio_url:
                        logger.info(f"文件上传到MinIO成功: {minio_url}")
                    else:
                        logger.error("文件上传到MinIO失败")
                        return jsonify({
                            "code": 500,
                            "success": False,
                            "message": "文件上传到MinIO失败",
                            "timestamp": int(time.time() * 1000),
                            "data": None
                        }), 500

                    # 同步转发到外部平台（仅当配置了 EXTERNAL_UPLOAD_URL）
                    try:
                        if EXTERNAL_UPLOAD_URL:
                            files = {
                                'soundRecording': (base_file_name, open(temp_file_path, 'rb'), 'audio/aac')
                            }
                            data = {
                                'deviceNo': device_no,
                                'chunkIndex': chunk_index,
                                'startTime': start_time,
                                'endTime': end_time,
                                'usrNo': usr_no,
                                'hasBody': str(has_body).lower(),
                                'extended': extended or '',
                                # 对方接口可能从表单字段读取文件名，而不是 Content-Disposition
                                'fileName': base_file_name,
                                'file_name': base_file_name
                            }
                            headers = {
                                'File-Name': base_file_name
                            }
                            resp = requests.post(EXTERNAL_UPLOAD_URL, files=files, data=data, headers=headers, timeout=15)
                            logger.info(f"外部上传返回: {resp.status_code} {resp.text[:200]}")
                    except Exception as e:
                        logger.warning(f"外部同步上传失败: {e}")
                else:
                    # 如果没有有效的文件，创建一个空文件并上传
                    temp_file_path = os.path.join(UPLOAD_FOLDER, base_file_name)
                    with open(temp_file_path, 'w') as f:
                        pass  # 创建空文件
                    file_size = os.path.getsize(temp_file_path)
                    logger.warning(f"未收到有效文件，创建空文件: {temp_file_path}")
                    local_audio_path = temp_file_path
                    
                    # 上传空文件到MinIO
                    minio_url = minio_manager.upload_file(temp_file_path, base_file_name)
                    if minio_url:
                        logger.info(f"空文件上传到MinIO成功: {minio_url}")
                    else:
                        logger.error("空文件上传到MinIO失败")
                        return jsonify({
                            "code": 500,
                            "success": False,
                            "message": "空文件上传到MinIO失败",
                            "timestamp": int(time.time() * 1000),
                            "data": None
                        }), 500
                    
            except Exception as e:
                logger.error(f"文件保存失败: {str(e)}", exc_info=True)
                return jsonify({
                    "code": 500,
                    "success": False,
                    "message": f"文件保存失败: {str(e)}",
                    "timestamp": int(time.time() * 1000),
                    "data": None
                }), 500
            
            # 同步阶段结束：仅入库源文件。后续改为异步处理
            processed_files = None
            
            # 保存到数据库（将处理后的文件列表转为JSON字符串）
            logger.info("开始保存到数据库...")
            processed_files_json = json.dumps(processed_files) if processed_files else None
            save_to_database(
                device_no, base_file_name, chunk_index, start_time, end_time, 
                usr_no, has_body, extended, minio_url, file_size
            )
            logger.info("文件信息保存完成")
            
            # 更新设备状态为上传中
            try:
                from database import update_device_status_on_upload
                if update_device_status_on_upload(device_no):
                    logger.info(f"设备 {device_no} 状态已更新为上传中")
                else:
                    logger.warning(f"设备 {device_no} 状态更新失败")
            except Exception as e:
                logger.error(f"更新设备 {device_no} 状态失败: {e}")

            # 状态更新为“待分析”(1) 并入队异步任务
            try:
                from database import update_sound_record_status
                update_sound_record_status(device_no, base_file_name, chunk_index, '1')
            except Exception:
                pass
            try:
                enqueue_job({
                    'device_no': device_no,
                    'base_file_name': base_file_name,
                    'chunk_index': chunk_index,
                    'minio_url': minio_url,
                    'time_pairs': time_pairs
                })
                logger.info("任务已提交至异步处理队列")
            except Exception as e:
                logger.error(f"入队失败: {e}")
            
            # 会话与分段处理交由异步流程
            
            logger.info("数据库保存完成")

            # 同步阶段不做情绪/会话文本处理，均交由异步线程
            
            # 构造成功响应
            response = {
                "code": 200,
                "success": True,
                "message": "文件上传处理完成" + ("(创建空文件)" if file_size == 0 else ""),
                "timestamp": int(time.time() * 1000),
                "data": {
                    "fileName": base_file_name,
                    "chunkIndex": chunk_index,
                    "fileSize": file_size,
                    "processedFiles": [os.path.basename(f["file_path"]) if isinstance(f, dict) else os.path.basename(f) for f in processed_files] if processed_files else None,
                    "processedCount": len(processed_files) if processed_files else 0
                }
            }
            
            logger.info(f"文件上传处理完成: {base_file_name} (分片 {chunk_index}), 大小: {file_size} 字节, 处理了 {len(processed_files) if processed_files else 0} 个片段")
            return jsonify(response)
            
        except Exception as e:
            logger.error(f"处理上传请求时发生错误: {str(e)}", exc_info=True)
            error_response = {
                "code": 500,
                "success": False,
                "message": f"服务器内部错误: {str(e)}",
                "timestamp": int(time.time() * 1000),
                "data": None
            }
            return jsonify(error_response), 500

    @app.route('/emotion/analyze', methods=['POST'])
    def analyze_emotion_by_url():
        """根据MinIO提供的录音URL进行情绪与ASR分析，返回文本内容"""
        try:
            body = request.get_json(silent=True) or {}
            audio_url = body.get('url') or request.args.get('url')
            if not audio_url:
                return jsonify({
                    "code": 400,
                    "success": False,
                    "message": "缺少参数: url",
                    "timestamp": int(time.time() * 1000),
                    "data": None
                }), 400

            # 从URL中提取对象名
            object_name = audio_url.rstrip('/').split('/')[-1]
            if not object_name:
                return jsonify({
                    "code": 400,
                    "success": False,
                    "message": "无效的URL",
                    "timestamp": int(time.time() * 1000),
                    "data": None
                }), 400

            # 准备本地临时文件与输出文件路径
            temp_audio_path = os.path.join(UPLOAD_FOLDER, f"emotion_tmp_{int(time.time()*1000)}_{object_name}")
            base_name_no_ext = os.path.splitext(object_name)[0]
            output_txt_path = os.path.join(SPEECHEMO_FOLDER, f"{base_name_no_ext}.txt")

            # 下载音频到本地
            minio_manager.client.fget_object(minio_manager.bucket_name, object_name, temp_audio_path)
            logger.info(f"情绪分析：已下载音频到 {temp_audio_path}")

            # 执行分析
            ok = process_audio_speech_emotion(temp_audio_path, output_txt_path)

            # 读取结果内容
            text_content = None
            if ok and os.path.exists(output_txt_path):
                with open(output_txt_path, 'r', encoding='utf-8') as f:
                    text_content = f.read()

            # 清理本地临时音频
            try:
                if os.path.exists(temp_audio_path):
                    os.remove(temp_audio_path)
            except Exception:
                pass

            if not ok:
                return jsonify({
                    "code": 500,
                    "success": False,
                    "message": "情绪/ASR分析失败",
                    "timestamp": int(time.time() * 1000),
                    "data": None
                }), 500

            return jsonify({
                "code": 200,
                "success": True,
                "message": "分析成功",
                "timestamp": int(time.time() * 1000),
                "data": {
                    "fileName": object_name,
                    "text": text_content
                }
            })

        except Exception as e:
            logger.error(f"处理情绪分析请求时发生错误: {str(e)}", exc_info=True)
            return jsonify({
                "code": 500,
                "success": False,
                "message": f"服务器内部错误: {str(e)}",
                "timestamp": int(time.time() * 1000),
                "data": None
            }), 500

    @app.route('/api/device/<device_no>/info', methods=['GET'])
    def get_device_info(device_no):
        """获取设备信息"""
        try:
            from database import get_device_info
            
            device_info = get_device_info(device_no)
            
            if device_info:
                # 添加状态文本说明
                status_text = "上传中" if device_info['device_status'] == '1' else "未上传"
                device_type_text = {
                    '1': '桌面终端',
                    '2': '胸牌', 
                    '3': '挂牌'
                }.get(device_info['device_type'], '未知')
                
                device_info['status_text'] = status_text
                device_info['device_type_text'] = device_type_text
                
                return jsonify({
                    "code": 200,
                    "success": True,
                    "message": "获取设备信息成功",
                    "timestamp": int(time.time() * 1000),
                    "data": device_info
                })
            else:
                return jsonify({
                    "code": 404,
                    "success": False,
                    "message": "设备不存在",
                    "timestamp": int(time.time() * 1000),
                    "data": None
                }), 404
                
        except Exception as e:
            logger.error(f"获取设备 {device_no} 信息失败: {e}")
            return jsonify({
                "code": 500,
                "success": False,
                "message": f"获取设备信息失败: {str(e)}",
                "timestamp": int(time.time() * 1000),
                "data": None
            }), 500

    @app.route('/api/device/<device_no>/status', methods=['POST'])
    def update_device_status_manual(device_no):
        """手动更新设备状态"""
        try:
            data = request.get_json() or {}
            status = data.get('status', '1')  # 默认为上传中
            
            from database import update_device_status_on_upload, update_device_status_to_offline
            
            if status == '1':
                success = update_device_status_on_upload(device_no)
                status_text = "上传中"
            elif status == '2':
                success = update_device_status_to_offline(device_no)
                status_text = "未上传"
            else:
                return jsonify({
                    "code": 400,
                    "success": False,
                    "message": "无效的状态值，支持的值：1(上传中), 2(未上传)",
                    "timestamp": int(time.time() * 1000),
                    "data": None
                }), 400
            
            if success:
                return jsonify({
                    "code": 200,
                    "success": True,
                    "message": f"设备 {device_no} 状态已更新为{status_text}",
                    "timestamp": int(time.time() * 1000),
                    "data": {
                        "device_no": device_no,
                        "status": status,
                        "status_text": status_text
                    }
                })
            else:
                return jsonify({
                    "code": 500,
                    "success": False,
                    "message": f"设备 {device_no} 状态更新失败",
                    "timestamp": int(time.time() * 1000),
                    "data": None
                }), 500
                
        except Exception as e:
            logger.error(f"手动更新设备 {device_no} 状态失败: {e}")
            return jsonify({
                "code": 500,
                "success": False,
                "message": f"更新设备状态失败: {str(e)}",
                "timestamp": int(time.time() * 1000),
                "data": None
            }), 500
